home *** CD-ROM | disk | FTP | other *** search
- TITLE "Large Integer Arithmetic"
- ;++
- ;
- ; Module Name:
- ;
- ; largeint.s
- ;
- ; Abstract:
- ;
- ; This module implements routines for performing extended integer
- ; arithmtic.
- ;
- ; Environment:
- ;
- ; Any mode.
- ;
- ; Revision History:
- ;
- ;--
-
- .386p
- .xlist
- include ks386.inc
- include callconv.inc ; calling convention macros
- .list
-
-
- _TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
- ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
-
- page ,132
- subttl "LargeIntegerAdd"
- ;++
- ;
- ; LARGE_INTEGER
- ; LargeIntegerAdd (
- ; IN LARGE_INTEGER Addend1,
- ; IN LARGE_INTEGER Addend2
- ; )
- ;
- ; Routine Description:
- ;
- ; This function adds a signed large integer to a signed large integer and
- ; returns the signed large integer result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = Addend1 - first addend value
- ; (TOS+12) = Addend2 - second addend value
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- cPublicProc _LargeIntegerAdd ,4
- cPublicFpo 4,0
-
- mov eax,[esp]+4 ; (eax)=add1.low
- add eax,[esp]+12 ; (eax)=sum.low
- mov edx,[esp]+8 ; (edx)=add1.hi
- adc edx,[esp]+16 ; (edx)=sum.hi
- stdRET _LargeIntegerAdd
-
- stdENDP _LargeIntegerAdd
-
-
- page
- subttl "Enlarged Integer Multiply"
- ;++
- ;
- ; LARGE_INTEGER
- ; EnlargedIntegerMultiply (
- ; IN LONG Multiplicand,
- ; IN LONG Multiplier
- ; )
- ;
- ; Routine Description:
- ;
- ; This function multiplies a signed integer by an signed integer and
- ; returns a signed large integer result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = Factor1
- ; (TOS+8) = Factor2
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- cPublicProc _EnlargedIntegerMultiply ,2
- cPublicFpo 2,0
-
- mov eax,[esp]+4 ; (eax) = factor1
- imul dword ptr [esp]+8 ; (edx:eax) = signed result
- stdRET _EnlargedIntegerMultiply
-
- stdENDP _EnlargedIntegerMultiply
-
-
- page
- subttl "Enlarged Unsigned Integer Multiply"
- ;++
- ;
- ; LARGE_INTEGER
- ; EnlargedUnsignedMultiply (
- ; IN ULONG Multiplicand,
- ; IN ULONG Multiplier
- ; )
- ;
- ; Routine Description:
- ;
- ; This function multiplies an un signed integer by an unsigned integer and
- ; returns a signed large integer result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = Factor1
- ; (TOS+8) = Factor2
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- cPublicProc _EnlargedUnsignedMultiply ,2
- cPublicFpo 2,0
-
- mov eax,[esp]+4 ; (eax) = factor1
- mul dword ptr [esp]+8 ; (edx:eax) = unsigned result
- stdRET _EnlargedUnsignedMultiply
-
- stdENDP _EnlargedUnsignedMultiply
-
- page
- subttl "Enlarged Unsigned Integer Divide"
-
- ;++
- ;
- ; ULONG
- ; EnlargedUnsignedDivide (
- ; IN ULARGE_INTEGER Dividend,
- ; IN ULONG Divisor,
- ; IN PULONG Remainder
- ; )
- ;
- ;
- ; Routine Description:
- ;
- ; This function divides an unsigned large integer by an unsigned long
- ; and returns the resultant quotient and optionally the remainder.
- ;
- ; N.B. It is assumed that no overflow will occur.
- ;
- ; Arguments:
- ;
- ; Dividend - Supplies the dividend value.
- ;
- ; Divisor - Supplies the divisor value.
- ;
- ; Remainder - Supplies an optional pointer to a variable that
- ; receives the remainder.
- ;
- ; Return Value:
- ;
- ; The unsigned long integer quotient is returned as the function value.
- ;
- ;--
-
- cPublicProc _EnlargedUnsignedDivide,4
- cPublicFpo 4,0
-
- mov eax, [esp+4] ; (eax) = Dividend.LowPart
- mov edx, [esp+8] ; (edx) = Dividend.HighPart
- mov ecx, [esp+16] ; (ecx) = pRemainder
- div dword ptr [esp+12] ; divide by Divisor
-
- or ecx, ecx ; return remainder?
- jnz short @f
-
- stdRET _EnlargedUnsignedDivide ; (eax) = Quotient
-
- align 4
- @@: mov [ecx], edx ; save remainder
- stdRET _EnlargedUnsignedDivide ; (eax) = Quotient
-
- stdENDP _EnlargedUnsignedDivide
-
- page
- subttl "Extended Large Integer Divide"
-
- ;++
- ;
- ; LARGE_INTEGER
- ; ExtendedLargeIntegerDivide (
- ; IN LARGE_INTEGER Dividend,
- ; IN ULONG Divisor,
- ; OUT PULONG Remainder OPTIONAL
- ; )
- ;
- ; Routine Description:
- ;
- ; This routine divides an unsigned 64 bit dividend by a 32 bit divisor
- ; and returns a 64-bit quotient, and optionally the 32-bit remainder.
- ;
- ;
- ; Arguments:
- ;
- ; Dividend - Supplies the 64 bit dividend for the divide operation.
- ;
- ; Divisor - Supplies the 32 bit divisor for the divide operation.
- ;
- ; Remainder - Supplies an optional pointer to a variable which receives
- ; the remainder
- ;
- ; Return Value:
- ;
- ; The 64-bit quotient is returned as the function value.
- ;
- ;--
-
- cPublicProc _ExtendedLargeIntegerDivide, 4
- cPublicFpo 4,3
-
- push esi
- push edi
- push ebx
-
- mov eax, [esp+16] ; (eax) = Dividend.LowPart
- mov edx, [esp+20] ; (edx) = Dividend.HighPart
-
- lid00: mov ebx, [esp+24] ; (ebx) = Divisor
- or ebx, ebx
- jz short lid_zero ; Attempted a divide by zero
-
- push ebp
-
- mov ecx, 64 ; Loop count
- xor esi, esi ; Clear partial remainder
-
- ; (edx:eax) = Dividend
- ; (ebx) = Divisor
- ; (ecx) = Loop count
- ; (esi) = partial remainder
-
- align 4
- lid10: shl eax, 1 ; (LowPart << 1) | 0
- rcl edx, 1 ; (HighPart << 1) | CF
- rcl esi, 1 ; (Partial << 1) | CF
-
- sbb edi, edi ; clone CF into edi (0 or -1)
-
- cmp esi, ebx ; check if partial remainder less then divisor
- cmc
- sbb ebp, ebp ; clone CF intp ebp
- or edi, ebp ; merge with remainder of high bit
-
- sub eax, edi ; merge quotient bit
- and edi, ebx ; Select divisor or 0
- sub esi, edi
-
- dec ecx ; dec interration count
- jnz short lid10 ; go around again
-
- pop ebp
- pop ebx
- pop edi
-
- mov ecx, [esp+20] ; (ecx) = Remainder
- or ecx, ecx
- jnz short lid20
-
- pop esi
- stdRET _ExtendedLargeIntegerDivide
-
- align 4
- lid20:
- mov [ecx], esi ; store remainder
- pop esi
- stdRET _ExtendedLargeIntegerDivide
-
- lid_zero:
- div dword ptr [esp+24] ; cause divide by zero exception
- pop ebx
- pop edi
- pop esi
- stdRET _ExtendedLargeIntegerDivide
- stdENDP _ExtendedLargeIntegerDivide
-
- page
- subttl "Extended Magic Divide"
- ;++
- ;
- ; LARGE_INTEGER
- ; ExtendedMagicDivide (
- ; IN LARGE_INTEGER Dividend,
- ; IN LARGE_INTEGER MagicDivisor,
- ; IN CCHAR ShiftCount
- ; )
- ;
- ; Routine Description:
- ;
- ; This function divides a signed large integer by an unsigned large integer
- ; and returns the signed large integer result. The division is performed
- ; using reciprocal multiplication of a signed large integer value by an
- ; unsigned large integer fraction which represents the most significant
- ; 64-bits of the reciprocal divisor rounded up in its least significant bit
- ; and normalized with respect to bit 63. A shift count is also provided
- ; which is used to truncate the fractional bits from the result value.
- ;
- ; Arguments:
- ;
- ; (ebp+8) = Dividend
- ; (ebp+16) = MagicDivisor value is a 64-bit multiplicative reciprocal
- ; (ebp+24) = ShiftCount - Right shift adjustment value.
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- RemdDiv equ [ebp+8] ; Dividend
- RemdRec equ [ebp+16] ; Reciprocal (magic divisor)
- RemdShift equ [ebp+24]
- RemdTmp1 equ [ebp-4]
- RemdTmp2 equ [ebp-8]
- RemdTmp3 equ [ebp-12]
-
- cPublicProc _ExtendedMagicDivide ,5
-
- push ebp
- mov ebp,esp
- sub esp,12
- push esi
-
- mov esi, RemdDiv+4
- test esi,80000000h
- jz remd10 ; no sign, no need to negate
-
- neg dword ptr RemdDiv+4
- neg dword ptr RemdDiv
- sbb dword ptr RemdDiv+4,0 ; negate
-
- remd10: mov eax,RemdRec
- mul dword ptr RemdDiv ; (edx:eax) = Div.lo * Rec.lo
- mov RemdTmp1,edx
-
- mov eax,RemdRec
- mul dword ptr RemdDiv+4 ; (edx:eax) = Div.hi * Rec.lo
- mov RemdTmp2,eax
- mov RemdTmp3,edx
-
- mov eax,RemdRec+4
- mul dword ptr RemdDiv ; (edx:eax) = Div.lo * Rec.hi
-
- ;
- ; Col 0 doesn't matter
- ; Col 1 = Hi(Div.lo * Rec.lo) + Low(Div.Hi * Rec.lo) + Low(Div.lo * Rec.hi)
- ; = RemdTmp1 + RemdTmp2 + eax
- ; -> Only want carry from Col 1
- ;
-
- xor ecx,ecx ; (ecx) = 0
- add eax,RemdTmp1
- adc ecx, 0 ; save carry in ecx
- add eax,RemdTmp2
- adc ecx, 0 ; Save Carry, all we want from Col2
-
- mov RemdTmp1,edx
-
- mov eax,RemdRec+4
- mul dword ptr RemdDiv+4 ; (edx:eax) = Div.Hi * Rec.Hi
-
- ;
- ; TOS = carry flag from Col 1
- ;
- ; Col 2 = Col1 CF +
- ; Hi(Div.Hi * Rec.Lo) + Hi(Div.Lo * Rec.Hi) + Low(Div.Hi * Rec.Hi)
- ; = CF + RemdTmp3 + RemdTmp1 + eax
- ;
- ; Col 3 = Col2 CF + Hi(Div.Hi * Rec.Hi)
- ; = CF + edx
- ;
-
- add eax,RemdTmp1
- adc edx, 0 ; add carry to edx
- add eax,RemdTmp3 ; (eax) = col 2
- adc edx, 0 ; add carry to edx
- add eax, ecx
- adc edx, 0 ; (edx) = col 3
-
- ;
- ; (edx:eax) = the high 64 bits of the multiply, shift it right by
- ; shift count to discard bits to right of virtual decimal pt.
- ;
- ; RemdShift could be as large as 63 and still not 0 the result, 386
- ; will only shift 31 bits at a time, so must do the sift multiple
- ; times to get correct effect.
- ;
-
- mov cl,RemdShift
- remd20: cmp cl,31
- jbe remd30
- sub cl,31
- shrd eax,edx,31
- shr edx,31
- jmp remd20
-
- remd30: shrd eax,edx,cl
- shr edx,cl
-
- ;
- ; Negate the result if need be
- ;
-
- test esi,80000000h
- jz remd40 ; no sign, go return without negate
-
- neg edx
- neg eax
- sbb edx,0
-
- ;
- ; Store the result
- ;
-
- remd40:
- ; results in (edx:eax)
-
- pop esi
- mov esp,ebp
- pop ebp
- stdRET _ExtendedMagicDivide
-
- stdENDP _ExtendedMagicDivide
-
-
- page
- subttl "Extended Integer Multiply"
- ;++
- ;
- ; LARGE_INTEGER
- ; ExtendedIntegerMultiply (
- ; IN LARGE_INTEGER Multiplicand,
- ; IN ULONG Multiplier
- ; )
- ;
- ; Routine Description:
- ;
- ; This function multiplies a signed large integer by a signed integer and
- ; returns the signed large integer result.
- ;
- ; Arguments:
- ;
- ; (ebp+8,12)=multiplican (MCAN)
- ; (ebp+16)=multiplier (MPER)
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- ReimMCAN equ [ebp+8]
- ReimMPER equ [ebp+16]
-
- cPublicProc _ExtendedIntegerMultiply ,3
-
- push ebp
- mov ebp,esp
- push esi
-
- mov esi,ReimMPER
- xor esi,ReimMCAN+4 ; (esi) = result sign
-
- test ReimMCAN+4,80000000h
- jz short reim10 ; MCAN pos, go look at MPER
-
- neg dword ptr ReimMCAN+4
- neg dword ptr ReimMCAN
- sbb dword ptr ReimMCAN+4,0 ; negate multiplican
-
- reim10: test ReimMPER,80000000h
- jz short reim20 ; MPER pos, go do multiply
-
- neg dword ptr ReimMPER ; negate multiplier
-
- reim20: mov eax,ReimMPER
- mul dword ptr ReimMCAN ; (edx:eax) = MPER * MCAN.low
- push edx
- mov ecx, eax
- mov eax,ReimMPER
- mul dword ptr ReimMCAN+4 ; (edx:eax) = MPER * MCAN.high
- add eax,[esp] ; (eax) = hi part of MPER*MCAN.low
- ; plus low part of MPER*MCAN.hi
-
- test esi,80000000h
- jz short reim30 ; result sign is OK, go return
-
- neg eax
- neg ecx
- sbb eax,0 ; negate result
-
- reim30: add esp,4 ; clean eax off stack
- pop esi ; restore nonvolatile reg
- mov edx,eax ; (edx:ecx) = result
- mov eax,ecx ; (edx:eax) = result
-
- pop ebp
- stdRET _ExtendedIntegerMultiply
-
- stdENDP _ExtendedIntegerMultiply
-
- page
- subttl "Large Integer Shift Left"
- ;++
- ;
- ; LARGE_INTEGER
- ; LargeIntegerShiftLeft (
- ; IN LARGE_INTEGER LargeInteger,
- ; IN CCHAR ShiftCount
- ; )
- ;
- ;
- ; Routine Description:
- ;
- ; This routine does a left logical shift of a large integer by a
- ; specified amount (ShiftCount) modulo 64.
- ;
- ; Arguments:
- ;
- ; LargeInteger - Supplies the large integer to be shifted
- ;
- ; ShiftCount - Supplies the left shift count
- ;
- ; Return Value:
- ;
- ; LARGE_INTEGER - Receives the shift large integer result
- ;
- ;--
- cPublicProc _LargeIntegerShiftLeft,3
- cPublicFpo 3,0
-
- mov ecx, [esp+12] ; (ecx) = ShiftCount
- and ecx, 3fh ; mod 64
-
- cmp ecx, 32
- jnc short sl10
- ;
- ; Shift count is less then 32 bits.
- ;
- mov eax, [esp+4] ; (eax) = LargeInteger.LowPart
- mov edx, [esp+8] ; (edx) = LargeInteger.HighPart
- shld edx, eax, cl
- shl eax, cl
-
- stdRET _LargeIntegerShiftLeft
-
- align 4
- sl10:
- ;
- ; Shift count is greater than or equal 32 bits - low half of result is zero,
- ; high half is the low half shifted left by remaining count.
- ;
- mov edx, [esp+4] ; (edx) = LargeInteger.LowPart
- xor eax, eax ; store lowpart
- shl edx, cl ; store highpart
-
- stdRET _LargeIntegerShiftLeft
-
- stdENDP _LargeIntegerShiftLeft
-
- page
- subttl "Large Integer Shift Right"
-
- ;--
- ;
- ;LARGE_INTEGER
- ;LargeIntegerShiftRight (
- ; IN LARGE_INTEGER LargeInteger,
- ; IN CCHAR ShiftCount
- ; )
- ;
- ;Routine Description:
- ;
- ; This routine does a right logical shift of a large integer by a
- ; specified amount (ShiftCount) modulo 64.
- ;
- ;Arguments:
- ;
- ; LargeInteger - Supplies the large integer to be shifted
- ;
- ; ShiftCount - Supplies the right shift count
- ;
- ;Return Value:
- ;
- ; LARGE_INTEGER - Receives the shift large integer result
- ;
- ;--*/
- cPublicProc _LargeIntegerShiftRight,3
- cPublicFpo 3,0
-
- mov ecx, [esp+12] ; (ecx) = ShiftCount
- and ecx, 3fh ; mod 64
-
- cmp ecx, 32
- jnc short sr10
-
- ;
- ; Shift count is less then 32 bits.
- ;
- mov eax, [esp+4] ; (eax) = LargeInteger.LowPart
- mov edx, [esp+8] ; (edx) = LargeInteger.HighPart
- shrd eax, edx, cl
- shr edx, cl
-
- stdRET _LargeIntegerShiftRight
-
- align 4
- sr10:
- ;
- ; Shift count is greater than or equal 32 bits - high half of result is zero,
- ; low half is the high half shifted right by remaining count.
- ;
- mov eax, [esp+8] ; (eax) = LargeInteger.HighPart
- xor edx, edx ; store highpart
- shr eax, cl ; store lowpart
-
- stdRET _LargeIntegerShiftRight
-
- stdENDP _LargeIntegerShiftRight
-
- ;++
- ;
- ;LARGE_INTEGER
- ;LargeIntegerArithmeticShift (
- ; IN LARGE_INTEGER LargeInteger,
- ; IN CCHAR ShiftCount
- ; )
- ;
- ;Routine Description:
- ;
- ; This routine does a right arithmetic shift of a large integer by a
- ; specified amount (ShiftCount) modulo 64.
- ;
- ;Arguments:
- ;
- ; LargeInteger - Supplies the large integer to be shifted
- ;
- ; ShiftCount - Supplies the right shift count
- ;
- ;Return Value:
- ;
- ; LARGE_INTEGER - Receives the shift large integer result
- ;
- ;--
- cPublicProc _LargeIntegerArithmeticShift,3
- cPublicFpo 3,0
-
- mov ecx, [esp+12] ; (ecx) = ShiftCount
- and ecx, 3fh ; mod 64
-
- cmp ecx, 32
- jc short sar10
-
- ;
- ; Shift count is greater than or equal 32 bits - high half of result is sign
- ; bit, low half is the high half shifted right by remaining count.
- ;
- mov eax, [esp+8] ; (eax) = LargeInteger.HighPart
- sar eax, cl ; store highpart
- bt eax, 31 ; sign bit set?
- sbb edx, edx ; duplicate sign bit into highpart
-
- stdRET _LargeIntegerArithmeticShift
-
- align 4
- sar10:
- ;
- ; Shift count is less then 32 bits.
- ;
- ;
- mov eax, [esp+4] ; (eax) = LargeInteger.LowPart
- mov edx, [esp+8] ; (edx) = LargeInteger.HighPart
- shrd eax, edx, cl
- sar edx, cl
-
- stdRET _LargeIntegerArithmeticShift
-
- stdENDP _LargeIntegerArithmeticShift,3
-
-
- page
- subttl "Large Integer Negate"
- ;++
- ;
- ; LARGE_INTEGER
- ; LargeIntegerNegate (
- ; IN LARGE_INTEGER Subtrahend
- ; )
- ;
- ; Routine Description:
- ;
- ; This function negates a signed large integer and returns the signed
- ; large integer result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = Subtrahend
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- cPublicProc _LargeIntegerNegate ,2
- cPublicFpo 2,0
-
- mov eax,[esp]+4 ; (eax) = lo
- mov edx,[esp]+8
- neg edx ; (edx) = 2's comp of hi part
- neg eax ; if ((eax) == 0) CF = 0
- ; else CF = 1
- sbb edx,0 ; (edx) = (edx) - CF
- ; (edx:eax) = result
- stdRET _LargeIntegerNegate
-
- stdENDP _LargeIntegerNegate
-
-
- page
- subttl "Large Integer Subtract"
- ;++
- ;
- ; LARGE_INTEGER
- ; LargeIntegerSubtract (
- ; IN LARGE_INTEGER Minuend,
- ; IN LARGE_INTEGER Subtrahend
- ; )
- ;
- ; Routine Description:
- ;
- ; This function subtracts a signed large integer from a signed large
- ; integer and returns the signed large integer result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = Minuend
- ; (TOS+12) = Subtrahend
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- cPublicProc _LargeIntegerSubtract ,4
- cPublicFpo 4,0
-
- mov eax,[esp]+4
- sub eax,[esp]+12 ; (eax) = result.low
- mov edx,[esp]+8
- sbb edx,[esp]+16 ; (edx) = result.high
- stdRET _LargeIntegerSubtract
-
- stdENDP _LargeIntegerSubtract
-
- page
- subttl "Convert Long to Large Integer"
- ;++
- ;
- ; LARGE_INTEGER
- ; ConvertLongToLargeInteger (
- ; IN LONG SignedInteger
- ; )
- ;
- ; Routine Description:
- ;
- ; This function converts the input signed integer to a signed large
- ; integer and returns the latter as the result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = SignedInteger
- ;
- ; Return Value:
- ;
- ; The large integer result is stored (edx:eax)
- ;
- ;--
-
- cPublicProc _ConvertLongToLargeInteger ,1
- cPublicFpo 1,0
-
- mov eax,[esp]+4 ; (eax) = SignedInteger
- cdq ; (edx:eax) = signed LargeInt
- stdRET _ConvertLongToLargeInteger
-
- stdENDP _ConvertLongToLargeInteger
-
-
- page
- subttl "Convert Ulong to Large Integer"
- ;++
- ;
- ; LARGE_INTEGER
- ; ConvertUlongToLargeInteger (
- ; IN LONG UnsignedInteger
- ; )
- ;
- ; Routine Description:
- ;
- ; This function converts the input unsigned integer to a signed large
- ; integer and returns the latter as the result.
- ;
- ; Arguments:
- ;
- ; (TOS+4) = UnsignedInteger
- ;
- ; Return Value:
- ;
- ; The large integer result is stored in (edx:eax)
- ;
- ;--
-
- cPublicProc _ConvertUlongToLargeInteger ,1
- cPublicFpo 1,0
-
- mov eax,[esp]+4 ; store low
- xor edx,edx ; store 0 in high
- stdRET _ConvertUlongToLargeInteger
-
- stdENDP _ConvertUlongToLargeInteger
-
-
- _TEXT ends
- end
-